package com.zmj.sy.mom.srv.aps.bean.bo.ado;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import com.zmj.sy.mom.srv.aps.bean.bo.ApsWeekDay;
import com.zmj.sy.mom.srv.aps.bean.entity.base.BaseEntity;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.*;
import com.zmj.sy.mom.srv.aps.utils.MkBeanUtils;
import com.zmj.sy.mom.srv.aps.utils.ProjectConstants;
import com.zmj.sy.mom.srv.aps.utils.SyExceptionUtils;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Getter
@Setter
public class AdoFactoryCache {

    private String factoryCode;
    private List<Group> groups = new ArrayList<>();
    private List<Station> stations = new ArrayList<>();

    private List<WeekdayRule> weekdayRules = new ArrayList<>();
    private List<ShiftType> shiftTypes = new ArrayList<>();
    private List<Shift> shifts = new ArrayList<>();
    private List<BreakPeriod> breakPeriods = new ArrayList<>();

    private List<AdoMachine> machines = new ArrayList<>();

    private LocalDate machineStartDate;
    private LocalDate machineEndDate;

    private Map<String, List<AdoMachine>> groupCodeMachineMap;
    private List<String> ignorePhaseCode;
    private Map<String, Phase> phaseCodeMap;



    public void initDay(LocalDate startDate, LocalDate endDate) {

        if (CollUtil.isEmpty(stations)) {
            throw SyExceptionUtils.e("没有初始化设备信息");
        }

        // 一般情况下，一包10天应该可以倒排，预留20天的缓冲区
        startDate = startDate.minusDays(20);

        machineStartDate = startDate;
        machineEndDate = endDate;

//        Map<Integer, StationWeekdayScheme> stationSchemeMap = stationWeekdaySchemes.stream().collect(Collectors.toMap(StationWeekdayScheme::getStationId, s -> s));
        Map<Integer, List<WeekdayRule>> stationRuleMap = weekdayRules.stream().collect(Collectors.groupingBy(WeekdayRule::getShiftTypeId));
        Map<Integer, List<Shift>> shiftMap = shifts.stream().collect(Collectors.groupingBy(Shift::getShiftTypeId));
        Map<Integer, List<BreakPeriod>> breakPeriodMap = breakPeriods.stream().collect(Collectors.groupingBy(BreakPeriod::getShiftId));
        Map<Integer, Group> groupIdMap = groups.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));

        int day = (int) startDate.until(endDate, ChronoUnit.DAYS);

        for (AdoMachine machine : machines) {
//            StationWeekdayScheme scheme = stationSchemeMap.get(machine.getStation());
            List<WeekdayRule> ruleList = stationRuleMap.get(groupIdMap.get(machine.getStation().getGroupId()).getShiftTypeId());
            if (CollUtil.isEmpty(ruleList)) {
                throw SyExceptionUtils.e(machine.getStation().getName() + "的班制没有规则信息");
            }
            if (machine.getWeekDays() == null) {
                machine.setWeekDays(new ArrayList<>());
            }
            List<Shift> machineShift = shiftMap.get(groupIdMap.get(machine.getStation().getGroupId()).getShiftTypeId());

            List<ApsWeekDay> allWeekday = Stream
                    .iterate(startDate, s -> s.plusDays(1))
                    .limit(day + 1L)
                    .flatMap(e ->
                            machineShift.stream()
                                    .map(shift -> {
                                        ApsWeekDay newDay = new ApsWeekDay();
                                        MkBeanUtils.copyPropertiesIgnore(shift, newDay);
                                        newDay.setSchemeId(groupIdMap.get(machine.getStation().getGroupId()).getShiftTypeId());
                                        newDay.setShiftDay(e);
                                        newDay.setShiftSeq(shift.getSeq());
                                        newDay.setShiftId(shift.getId());
                                        newDay.setStartDateTime(LocalDateTime.of(e.plusDays(shift.getOffsetStartDay()), shift.getStartTime()));
                                        newDay.setEndDateTime(LocalDateTime.of(e.plusDays(shift.getOffsetEndDay()), shift.getEndTime()));
                                        return newDay;
                                    })
                                    .flatMap(newDay -> {

                                        List<BreakPeriod> bp = breakPeriodMap.getOrDefault(newDay.getShiftId(), new ArrayList<>());
                                        List<ApsWeekDay> all = new ArrayList<>();
                                        for (BreakPeriod breakPeriod : bp) {
                                            if (LocalDateTime.of(e.plusDays(breakPeriod.getOffsetStartDay()), breakPeriod.getStartTime()).isAfter(newDay.getEndDateTime())) {
                                                continue;
                                            }
                                            if (LocalDateTime.of(e.plusDays(breakPeriod.getOffsetEndDay()), breakPeriod.getEndTime()).isBefore(newDay.getStartDateTime())) {
                                                continue;
                                            }
                                            ApsWeekDay apsWeekDay = MkBeanUtils.copyProperties(newDay, ApsWeekDay.class);
                                            apsWeekDay.setEndDateTime(LocalDateTime.of(e.plusDays(breakPeriod.getOffsetStartDay()), breakPeriod.getStartTime()));
                                            all.add(apsWeekDay);
                                            newDay.setStartDateTime(LocalDateTime.of(e.plusDays(breakPeriod.getOffsetEndDay()), breakPeriod.getEndTime()));
                                        }
                                        all.add(newDay);
                                        return all.stream();
                                    })


                    )
                    .sorted(Comparator.comparing(ApsWeekDay::getStartDateTime))
                    .collect(Collectors.toList());


            for (ApsWeekDay w : allWeekday) {
                for (WeekdayRule weekdayRule : ruleList) {
                    if (weekdayRule.getType() == 4) {
                        if (weekdayRule.getValue().equals(String.valueOf(w.getShiftDay().getDayOfWeek().getValue()))) {
                            w.setDateType(weekdayRule.getDateType());
                            w.setWorkState(weekdayRule.getStatus());
                            w.setWeekdayRuleId(weekdayRule.getId());
                        }
                    } else if (weekdayRule.getType() == 1) {
                        String value = weekdayRule.getValue();
                        String[] split = value.split(ProjectConstants.WEEKDAY_RULE_WEEKVALUE_SPLIT);
                        LocalDate start = LocalDate.parse(split[0], DatePattern.NORM_DATE_FORMATTER);
                        LocalDate end = LocalDate.parse(split[1], DatePattern.NORM_DATE_FORMATTER);
                        if (!w.getShiftDay().isBefore(start) && !w.getShiftDay().isAfter(end)) {
                            w.setDateType(weekdayRule.getDateType());
                            w.setWorkState(weekdayRule.getStatus());
                            w.setText(weekdayRule.getText());
                            w.setWeekdayRuleId(weekdayRule.getId());
                        }

                    } else if (weekdayRule.getType() == 3) {
                        if (LocalDate.parse(weekdayRule.getValue(), DatePattern.NORM_DATE_FORMATTER).equals(w.getShiftDay())) {
                            w.setDateType(weekdayRule.getDateType());
                            w.setWorkState(weekdayRule.getStatus());
                            w.setText(weekdayRule.getText());
                            w.setWeekdayRuleId(weekdayRule.getId());
                        }
                    } else if (weekdayRule.getType() == 2) {
                        String value = weekdayRule.getValue();
                        String[] split = value.split(ProjectConstants.WEEKDAY_RULE_WEEKVALUE_SPLIT);
                        if (split[0].equals(w.getShiftDay().toString()) && split[1].equals(String.valueOf(w.getShiftId()))) {
                            w.setDateType(weekdayRule.getDateType());
                            w.setWorkState(weekdayRule.getStatus());
                            w.setText(weekdayRule.getText());
                            w.setWeekdayRuleId(weekdayRule.getId());
                        }
                    }
                }
            }


            List<ApsWeekDay> collect = allWeekday.stream().filter(w -> w.getWorkState().equals(1)).collect(Collectors.toList());

            machine.getWeekDays().addAll(collect);
        }


    }

}
